package BNS.graphs;

import java.awt.Component;
import java.util.Date;
import java.util.Random;

import javax.swing.JOptionPane;


/** an extension to the Graph class that provides a way of generating 
	a Graph using the Preferential Attachment scheme described in 
	"Emergence of Scaling in Random Networks" by Barabasi and Albert, 
	www.sciencemag.org, Science vol 296, 15 October 1999.
	*/
public class PrefAttachGraph extends AnnotatedGraph {
	/**
   * 
   */
  private static final long serialVersionUID = 1L;
  // TODO: remove these special annotation values and put them in Properties
	//		(See notes in Graph and AnnotatedGraph.)
	public final String params, comment;
	public final int chromaticNumber, diameter, dominationRadius;
	public final double clusterQuotient;
	public final java.util.Date creationDate;
	
	/** returns a String containing various factoids about this graph,
		composed from the various annotation variables.
		Intended only for human consumption. 
		TODO: This method should be replaced by access to Graph properties.
		*/
	public String getInfo() {
		return params +" "+ comment +"\n"
		+" chromaticNumber="+ chromaticNumber
		+" diameter="+ diameter
		+" date= "+ creationDate;
		}
	
	/** a driver to test the other methods in this class.
		It requires 2 parameters: m0 and size
		If they appear on the command line, they will be used;
		otherwise a GUI pane will appear to prompt the user for them.
		In either case, stuff is printed but not saved anywhere.
		*/
	public static void main(String[] args) {
		PrefAttachGraph gr;
		if (args.length==2) {
			int m0= Integer.parseInt(args[0]);
			int size= Integer.parseInt(args[1]);
			gr= new PrefAttachGraph(m0, size, "test");
			}
		else gr= create(null);
		if (gr!=null) {
			System.err.println("PrefAttachGraph "+ gr.params);
			System.err.println(gr.creationDate);
			System.err.println(gr.comment);
			if(gr.numNodes()<20) gr.prettyPrint(System.err);
			else gr.histoDegrees(System.err);
			}
		}
	
	/** sets up a GUI dialog to obtain the needed parameters,
		then constructs a PrefAttachGraph using them and returns it.
		*/
	public static PrefAttachGraph create(Component frame) {
		try {
			String params= (String)JOptionPane.showInputDialog(frame, 
							   "enter 2 parameters separated by commas:\n"
							   +"m0,size",
							   "Creating PrefAttach Graph",
							   JOptionPane.QUESTION_MESSAGE);
			String[] param= params.split(",");
			int m0= Integer.parseInt(param[0]);
			int size= Integer.parseInt(param[1]);
			String comment="";
			if (param.length>2) comment=param[2];
			return new PrefAttachGraph(m0, size, comment);
			}
		catch (Exception e) { return null; }
		}
	
	/** creates a random graph using the Preferential Attachment scheme
		referred to in the class notes.
		@param m0 the outdegree of every node (except the first m0 nodes)
		@param size the total number of nodes wanted
		@param comment an arbitrary note for describing the graph
		*/
	public PrefAttachGraph(int m0, int size, String comment) {
		super(size, m0*(size-m0));
		System.err.println("generating PrefAttachGraph "+ m0 +", "+ size);
		System.err.println("generator NOT WORKING!");
		assert(size== -123);
		creationDate= new Date();
		this.params= m0 +","+ size;
		this.comment= comment;

		Random rand= new Random();
		Node[] nod= new Node[size];
		// Note '?' and 0 are default values for node class and status quo color, respectively.
		for(int t=0; t<size; t++) nod[t]= addNode("n"+(t+1), '?', 0);
		for(int t=0; t<m0; t++) addEdge(nod[m0],nod[t]);

		int[] connections= new int[size];
		for(int t=m0+1; t<size; t++) {
			for(int i=0; i<t; i++) 
				connections[i]= nod[i].degree();
			int edgeCount= 2*numEdges();
			for(int out=0; out<m0; out++) {
				int r= 1+rand.nextInt(edgeCount);
				int findi=0, findt=0;
				while(findt+connections[findi]< r)
					findt+= connections[findi++];
				System.err.print(edgeCount +" edges: ");
				for(int j=0; j<t; j++) System.err.print("  "+connections[j]);
				System.err.println("\t\tr="+r+" <= "+(findt+connections[findi])
								   +" so "+findi);
				System.out.print(","+t+"-"+findi);
				
				assert(addEdge(nod[t],nod[findi])!=null);
				
				edgeCount-= connections[findi];
				connections[findi]= 0;
				}
			}
		chromaticNumber= 0;			// TODO: make this meaningful
		diameter= 0;				// TODO: make this meaningful
		dominationRadius= 0;		// TODO: make this meaningful
		clusterQuotient= 0.;		// TODO: make this meaningful
		}
	
	}
